package com.superhelper.superhelper_web.service;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;

import com.superhelper.common.domain.AuserShop;
import com.superhelper.common.domain.TakeOutOrderType;
import com.superhelper.common.domain.TakeOutShopInfo;
import com.superhelper.common.service.RedisService;
import com.superhelper.common.utils.JsonHelper;
import com.superhelper.superhelper_web.common.Consts;
import com.superhelper.superhelper_web.domain.AccessToken;
import com.superhelper.superhelper_web.mapper.AdminMapper;

import eleme.openapi.sdk.api.entity.message.OMessage;
import eleme.openapi.sdk.api.entity.order.OOrder;
import eleme.openapi.sdk.api.entity.shop.OShop;
import eleme.openapi.sdk.api.enumeration.order.OInvalidateType;
import eleme.openapi.sdk.api.enumeration.shop.OShopProperty;
import eleme.openapi.sdk.api.exception.ServiceException;
import eleme.openapi.sdk.api.exception.UnauthorizedException;
import eleme.openapi.sdk.api.service.MessageService;
import eleme.openapi.sdk.api.service.OrderService;
import eleme.openapi.sdk.api.service.ShopService;
import eleme.openapi.sdk.api.service.UserService;
import eleme.openapi.sdk.config.Config;
import eleme.openapi.sdk.oauth.OAuthClient;
import eleme.openapi.sdk.oauth.response.Token;

@Service
public class ElemeService {
	protected Logger log = LoggerFactory.getLogger(this.getClass());
	@Value("${eleme.app_key}")
	private String eleme_app_key;
	@Value("${eleme.app_secret}")
	private String eleme_app_secret;
	@Value("${eleme.callback_url}")
	private String eleme_callback_url;
	@Value("${eleme.send_box}")
	private boolean eleme_send_box;
	@Autowired
	private RedisService redisService;
	@Autowired
	private AdminMapper adminMapper;

	public OAuthClient getOAuthClient() {
		// 实例化一个配置类
		Config config = getConfig();
		// 使用config对象，实例化一个授权类
		return new OAuthClient(config);
	}

	public Config getConfig() {
		// 实例化一个配置类
		return new Config(eleme_send_box, eleme_app_key, eleme_app_secret);
	}

	public String getAuthUrl(Integer auserId) {
		String scope = "all";
		String state = String.valueOf(auserId);
		return this.getOAuthClient().getAuthUrl(eleme_callback_url, scope,
				state);
	}

	public Token getTokenByCode(String authCode) {
		return this.getOAuthClient().getTokenByCode(authCode,
				eleme_callback_url);
	}

	public String getShopId(Token token) throws ServiceException {
		UserService userService = new UserService(this.getConfig(), token);
		Long shopId = userService.getUser().getAuthorizedShops().get(0).getId();
		return String.valueOf(shopId);
	}

	public Token getTokenByRefreshToken(String refreshToken) {
		return this.getOAuthClient().getTokenByRefreshToken(refreshToken);
	}

	public TakeOutShopInfo getShopInfo(String shopId) throws ServiceException {
		Token token = this.getToken(shopId);
		if (token != null) {
			ShopService shopService = new ShopService(this.getConfig(), token);
			OShop shop = null;
			try {
				shop = shopService.getShop(Long.parseLong(shopId));
			} catch (UnauthorizedException e) {
				if (e.getMessage().contains("token认证失败")) {
					token = this
							.getTokenByRefreshToken(token.getRefreshToken());
					String token_key = Consts.Cache.ELEME_TOKEN + shopId;
					AccessToken accessToken = new AccessToken();
					accessToken.setExpires(token.getExpires());
					accessToken.setRefreshToken(token.getRefreshToken());
					accessToken.setTokenType(token.getTokenType());
					accessToken.setToken(token.getAccessToken());
					accessToken.setTokenAt(new Date());
					accessToken.setShopId(shopId);
					adminMapper.updateShopToken(shopId, AuserShop.SHOP_ELEME,
							JsonHelper.toJson(accessToken));
					redisService.set(token_key, accessToken);
					shopService = new ShopService(this.getConfig(), token);
					shop = shopService.getShop(Long.parseLong(shopId));
				}
			}
			TakeOutShopInfo info = new TakeOutShopInfo();
			info.setShop_type(AuserShop.SHOP_ELEME);
			info.setePoiId(shopId);
			info.setPictureUrl(shop.getImageUrl());
			info.setName(shop.getName());
			info.setAddress(shop.getAddressText());
			if (shop.getPhones().size() > 0) {
				info.setPhone(shop.getPhones().get(0));
			}
			info.setIsOpen(shop.getIsOpen());
			info.setLatitude(shop.getLatitude());
			info.setLongitude(shop.getLongitude());
			return info;
		}
		return null;
	}

	/**
	 * 授权码(企业)模式刷新Token
	 * 
	 * @throws ServiceException
	 */
	public Token getToken(String shopId) throws ServiceException {
		// 后期优化，放缓存token
		String token_key = Consts.Cache.ELEME_TOKEN + shopId;
		AccessToken accessToken = redisService
				.get(token_key, AccessToken.class);
		if (accessToken != null) {
			long time = System.currentTimeMillis() / 1000;
			long tokenFlashTime = accessToken.getTokenAt().getTime() / 1000;
			if (time - tokenFlashTime >= (accessToken.getExpires() - 5 * 60)) {// token
				Token token = this.getTokenByRefreshToken(accessToken
						.getRefreshToken()); // 过期，提前5分钟
				if (token.isSuccess()) {
					accessToken = new AccessToken();
					accessToken.setExpires(token.getExpires());
					accessToken.setRefreshToken(token.getRefreshToken());
					accessToken.setTokenType(token.getTokenType());
					accessToken.setToken(token.getAccessToken());
					accessToken.setTokenAt(new Date());
					accessToken.setShopId(shopId);
					adminMapper.updateShopToken(shopId, AuserShop.SHOP_ELEME,
							JsonHelper.toJson(accessToken));
					redisService.set(token_key, accessToken);
					return token;
				} else {
					throw new ServiceException(token.getError(),
							token.getError_description());
				}
			} else {

				Token token = new Token();
				token.setAccessToken(accessToken.getToken());
				token.setExpires(accessToken.getExpires());
				token.setRefreshToken(accessToken.getRefreshToken());
				token.setTokenType(accessToken.getTokenType());
				return token;
			}
		} else {
			AuserShop s = adminMapper.getAuserShopByShopId(shopId,
					AuserShop.SHOP_ELEME);
			accessToken = JsonHelper.fromJson(s.getToken(), AccessToken.class);
			redisService.set(token_key, accessToken);

			Token token = new Token();
			token.setAccessToken(accessToken.getToken());
			token.setExpires(accessToken.getExpires());
			token.setRefreshToken(accessToken.getRefreshToken());
			token.setTokenType(accessToken.getTokenType());
			return token;
		}
	}

	public boolean confirmOrder(String shopId, String orderId)
			throws ServiceException {

		Token token = this.getToken(shopId);
		if (token != null) {
			OrderService orderService = new OrderService(this.getConfig(),
					token);
			OOrder order = orderService.confirmOrder(orderId);
			log.info("confirmOrder result:{}", JsonHelper.toJson(order));
		}
		return true;

	}

	public boolean cancelOrder(String shopId, String orderId)
			throws ServiceException {

		Token token = this.getToken(shopId);
		if (token != null) {
			OrderService orderService = new OrderService(this.getConfig(),
					token);
			OOrder order = orderService.cancelOrder(orderId,
					OInvalidateType.others, "");
			log.info("cancelOrder result:{}", JsonHelper.toJson(order));
		}
		return true;

	}

	public boolean agreeRefund(String shopId, String orderId)
			throws ServiceException {

		Token token = this.getToken(shopId);
		if (token != null) {
			OrderService orderService = new OrderService(this.getConfig(),
					token);
			OOrder order = orderService.agreeRefund(orderId);
			log.info("agreeRefund result:{}", JsonHelper.toJson(order));
		}
		return true;
	}

	public boolean disagreeRefund(String shopId, String orderId)
			throws ServiceException {

		Token token = this.getToken(shopId);
		if (token != null) {
			OrderService orderService = new OrderService(this.getConfig(),
					token);
			OOrder order = orderService.disagreeRefund(orderId, "");
			log.info("disagreeRefund result:{}", JsonHelper.toJson(order));
		}
		return true;
	}

	public boolean openShop(String shopId, Integer state)
			throws ServiceException {
		Token token = this.getToken(shopId);
		if (token != null) {
			ShopService shopService = new ShopService(this.getConfig(), token);
			Map<OShopProperty, Object> properties = new HashMap<OShopProperty, Object>();
			properties.put(OShopProperty.isOpen, state);
			OShop shop = shopService.updateShop(Long.parseLong(shopId),
					properties);
			log.info("openShop result:{}", JsonHelper.toJson(shop));
			return true;
		}
		return false;
	}

	public String getOrderStatus(String shopId, String orderId)
			throws ServiceException {

		Token token = this.getToken(shopId);
		if (token != null) {
			OrderService orderService = new OrderService(this.getConfig(),
					token);
			OOrder order = orderService.getOrder(orderId);
			log.info("getOrderStatus result:{}", JsonHelper.toJson(order));
			return order.getStatus().name();
		}
		return null;
	}

}
